package com.cxyd.modules.wcs.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.cxyd.common.constant.RcsConstants;
import com.cxyd.common.constant.WcsConstants;
import com.cxyd.common.service.impl.CrudServiceImpl;
import com.cxyd.modules.api.dto.RcsResultHK;
import com.cxyd.modules.log.service.SysLogWorkService;
import com.cxyd.modules.wcs.dao.AgvCallbackHkDao;
import com.cxyd.modules.wcs.dao.StockDao;
import com.cxyd.modules.wcs.dto.AgvCallbackHkDTO;
import com.cxyd.modules.wcs.entity.*;
import com.cxyd.modules.wcs.service.*;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Map;

@Service
public class AgvCallbackHkServiceImpl extends CrudServiceImpl<AgvCallbackHkDao, AgvCallbackHkEntity, AgvCallbackHkDTO> implements AgvCallbackHkService {
    @Resource
    private AgvTrkHkService hkService;
    @Resource
    private TrkService trkService;
    @Resource
    private StockService stockService;
    @Resource
    private PcItemService pcService;
    @Resource
    private StnMappingService stnMappingService;
    @Resource
    private SysLogWorkService logWorkService;
    @Resource
    private StockDao stockDao;

    @Override
    public QueryWrapper<AgvCallbackHkEntity> getWrapper(Map<String, Object> params) {
        return null;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public RcsResultHK callbackHandle(AgvCallbackHkDTO dto) {
        //        1.对json报文进行解析(获取reqCode,taskCode,robotCode,method,currentPositionCode)
        String reqCode = dto.getReqCode();
        String taskCode = dto.getTaskCode();
        String robotCode = dto.getRobotCode();
        String method = dto.getMethod();
//        当前站点信息
        String positionCode = dto.getWbCode();
//        根据taskCode获取任务信息
        AgvTrkHkEntity task = hkService.getAgvTrkByTaskCode(taskCode);
        if (task == null) {
            //不存在的任务单号,视为RCS主动向WCS上报到位信息
            RcsUpRequest(dto);
            return new RcsResultHK().success(reqCode);
        }
//        记录车号
        task.setAgvCode(robotCode);
//        不同的method调用不同的处理逻辑
        if (RcsConstants.HK_METHOD_START.equals(method)) {
//       1.任务开始(更新任务当前状态0-初始 1-任务下发 2-任务开始 3-搬送中 4-任务完成 9-任务取消)
            agvTrkStart(task, positionCode);
        } else if (RcsConstants.HK_METHOD_OUTBIN.equals(method)) {
//      2.走出储位(可认为是下架)
            agvTrkOutbin(task, positionCode);
        } else if (RcsConstants.HK_METHOD_OUTBIN11.equals(method)) {
            //托盘从站台离开后，需要将站台状态清空
            StnMappingEntity startEntity = stnMappingService.getStnByNo(dto.getWbCode());
            if (ObjectUtils.isNotEmpty(startEntity)) {
                startEntity.setStatus(0);
                startEntity.setContNo("");
                startEntity.setUpdater(WcsConstants.WCS_USER_ID);
                startEntity.setUpdateDate(new Date());
                stnMappingService.updateById(startEntity);
            }
            //如果有优先级低的任务，就将其状态改为待执行
            List<AgvTrkHkEntity> list = hkService.selectAll();
            for (AgvTrkHkEntity agvTrkHkEntity : list) {
                if (agvTrkHkEntity.getCtnrTyp().equals(task.getCtnrTyp()) && agvTrkHkEntity.getStatus() == 6) {
                    agvTrkHkEntity.setStatus(0);
                    hkService.updateById(agvTrkHkEntity);
                }
            }
        }  else if (RcsConstants.HK_METHOD_END.equals(method)) {
//      3.任务结束
            agvTrkEnd(task, positionCode);
        } else {

        }
        return new RcsResultHK().success(reqCode);
    }

    /***
     * 任务开始
     * @param task
     */
    private void agvTrkStart(AgvTrkHkEntity task, String positionCode) {
        String workName = "[流程-4]任务开始-HK";
        String workProc = "AgvCallbackHkServiceImpl.agvTrkStart";
        String pCode = WcsConstants.PROC_CODE_SUCCESS;
        String pMsg = "小车[" + task.getAgvCode() + "]准备从站点[" + positionCode + "]搬送料箱[" + task.getCtnrCode() + "]!method为[start]";
//        start时并未执行该任务,只是说CTU接到有任务而已
        task.setStatus(RcsConstants.TASK_STATUS_RUNNING);
        task.setCurrentPositionCode(positionCode);
        task.setData("RCS接收任务后开始执行!method-[start]");
        task.setUpdater(WcsConstants.WCS_USER_ID);
        task.setUpdateDate(new Date());
        hkService.updateById(task);

        //货架-站台的任务执行时，需要通知 plc任务状态
        PcItemEntity pcEntity = pcService.getPcItemByCode(task.getCtnrTyp(), "PC_REQ_STATUS");
        pcEntity.setItemValue(String.valueOf(RcsConstants.TASK_STATUS_RUNNING));
        pcEntity.setStatus(1);
        pcEntity.setUpdateDate(new Date());
        pcService.updateById(pcEntity);


//        找到对应[wcs_trk]任务进行更新
        TrkEntity trkEntity = trkService.selectById(task.getTrkId());
        if (trkEntity == null) {
            return;
        }
        trkEntity.setComments(pMsg);
        trkEntity.setUpdater(WcsConstants.WCS_USER_ID);
        trkEntity.setUpdateDate(new Date());
        trkService.updateById(trkEntity);
//        以料箱维度记录日志
        logWorkService.workLogging(workName, task.getCtnrCode(), pCode,
                pMsg, null, workProc, WcsConstants.WCS_USER_NAME, 10L);
    }

    /***
     * 走出储位（一般为出库下架）
     * @param task
     */
    private void agvTrkOutbin(AgvTrkHkEntity task, String positionCode) {
//        通知wms料箱已下架等
        String workName = "[流程-2]小车取放请求";
        String workProc = "AgvCallbackHkServiceImpl.agvTrkOutbin";
        String pCode = WcsConstants.PROC_CODE_SUCCESS;
        String pMsg = "小车[" + task.getAgvCode() + "]搬送料箱[" + task.getCtnrCode() + "]在[" + positionCode + "]申请放料!method为[outbin]";
//        取放时向线体申请可入信号(根据所搬送的托盘类型判断)-更新[pc_item]信息
        String contType = task.getCtnrTyp();
        //根据料箱类型判断向哪个站点请求可入信号
        PcItemEntity pcEntity = pcService.getPcItemByCode(contType, "PC_APPLY");
        pcEntity.setItemValue("1");
        pcEntity.setStatus(1);
        pcEntity.setUpdateDate(new Date());
        pcService.updateById(pcEntity);

        task.setStatus(RcsConstants.TASK_STATUS_APPLY); //任务状态
        task.setData("AGV申请可入信号!");
        task.setUpdateDate(new Date());
        hkService.updateById(task);

        //需要通知 plc任务状态
        PcItemEntity pcItemEntity = pcService.getPcItemByCode(contType, "PC_REQ_STATUS");
        pcItemEntity.setItemValue(String.valueOf(RcsConstants.TASK_STATUS_APPLY));
        pcItemEntity.setStatus(1);
        pcService.updateById(pcItemEntity);


        logWorkService.workLogging(workName, task.getCtnrCode(), pCode,
                pMsg, null, workProc, WcsConstants.WCS_USER_NAME, 10L);
    }

    /***
     * 任务结束(将对应agv搬送任务完成并转移历史)
     * @param task
     */
    private void agvTrkEnd(AgvTrkHkEntity task, String positionCode) {
        String workName = "[流程-4]任务结束-HK";
        String workProc = "AgvCallbackHkServiceImpl.agvTrkEnd";
        String pCode = WcsConstants.PROC_CODE_SUCCESS;
        String pMsg = "小车[" + task.getAgvCode() + "]搬送料箱[" + task.getCtnrCode() + "]到达站点[" + positionCode + "]!method为[end]";
//      获取[wcs_trk]信息
        task.setStatus(RcsConstants.TASK_STATUS_END); //任务完成
        task.setCurrentPositionCode(positionCode);
        task.setUpdateDate(new Date());
        hkService.updateById(task);
        TrkEntity trkEntity = trkService.selectById(task.getTrkId());
        if (trkEntity == null) {
            return;
        }
//        任务完成后将入库申请信号点清除
        //根据料箱类型判断向哪个站点请求可入信号
        PcItemEntity pcEntity = pcService.getPcItemByCode(task.getCtnrTyp(),"PC_APPLY");
        pcEntity.setItemValue("0");
        pcEntity.setStatus(1);
        pcEntity.setUpdateDate(new Date());
        pcService.updateById(pcEntity);

        //任务结束后，要将起点终点状态更新掉
        StnMappingEntity endEntity = stnMappingService.getStnByNo(trkEntity.getToPos());
        //更新库存表 wcs_stock
        if (!endEntity.getStationType().equals("ST")) {
            StockEntity endStock = new StockEntity();
            endStock.setContNo(task.getCtnrCode());
            endStock.setPositionType(endEntity.getStationType());
            endStock.setCurPosition(positionCode);
            endStock.setStockQty(BigDecimal.valueOf(1));
            endStock.setCreator(WcsConstants.WCS_USER_ID);
            endStock.setUpdater(WcsConstants.WCS_USER_ID);
            endStock.setCreateDate(new Date());
            stockService.insert(endStock);
        }

        endEntity.setStatus(2);
        endEntity.setContNo(trkEntity.getContNo());
        endEntity.setUpdater(WcsConstants.WCS_USER_ID);
        endEntity.setUpdateDate(new Date());
        stnMappingService.updateById(endEntity);


        //货架-站台的任务结束时，需要通知 plc任务状态，如果库存表wcs_stock有数据，需要清掉，stnMapping表也需更新掉
        if (task.getTaskTyp().equals("M1")) {
            List<StockEntity> stockEntities = stockDao.selectList(new QueryWrapper<StockEntity>().lambda().eq(StockEntity::getCurPosition, trkEntity.getFrmPos()));
            if (ObjectUtils.isNotEmpty(stockEntities)) {
                for (StockEntity stockEntity : stockEntities) {
                    stockService.deleteById(stockEntity.getId());
                }
            }

            StnMappingEntity startEntity = stnMappingService.getStnByNo(trkEntity.getFrmPos());
            if (ObjectUtils.isNotEmpty(startEntity)) {
                startEntity.setStatus(0);
                startEntity.setContNo("");
                startEntity.setUpdater(WcsConstants.WCS_USER_ID);
                startEntity.setUpdateDate(new Date());
                stnMappingService.updateById(startEntity);
            }
            //需要通知 plc任务状态
            PcItemEntity pcItemEntity = pcService.getPcItemByCode(task.getCtnrTyp(), "PC_REQ_STATUS");
            pcItemEntity.setItemValue("0");
            pcItemEntity.setStatus(1);

            pcService.updateById(pcItemEntity);
        }

        //如果是送到站台的任务，任务完成时需要通知 plc任务执行完成
        if (endEntity.getStationType().equals("ST")) {
            PcItemEntity endPcEntity = pcService.getPcItemByCode(task.getCtnrTyp(),"PC_FINISH");
            endPcEntity.setItemValue("1");
            endPcEntity.setStatus(1);
            endPcEntity.setUpdateDate(new Date());
            pcService.updateById(endPcEntity);
        }
        trkEntity.setTrkSt(WcsConstants.TRK_STATUS_DONE);
        trkEntity.setComments(pMsg);
        trkEntity.setCurPos(positionCode);
        trkEntity.setUpdater(WcsConstants.WCS_USER_ID);
        trkEntity.setUpdateDate(new Date());
        trkService.updateById(trkEntity);
        //数据处理完毕后将agv_trk_hk的任务做转移(此处不再转移,当任务上报完成后再转移)
        logWorkService.workLogging(workName, task.getCtnrCode(), pCode,
                pMsg, null, workProc, WcsConstants.WCS_USER_NAME, 10L);
    }

    /**
     * RCS主动向WCS上报到位信息
     *
     * @param dto
     */
    private void RcsUpRequest(AgvCallbackHkDTO dto) {
        if (dto == null) {
            return;
        }
        String workName = "[流程-0]上架请求-HK";
        String workProc = "AgvCallbackHkServiceImpl.RcsActiveRequest";
        String pCode = WcsConstants.PROC_CODE_SUCCESS;
        String pMsg = "小车[" + dto.getRobotCode() + "]搬送[" + dto.getMethod() + "]到达区域[" + dto.getCurrentPositionCode() + "]!";
        //根据位置currentPositionCode匹配一下stn_mapping中的
        StnMappingEntity stnEntity = stnMappingService.getStnByNo(dto.getCurrentPositionCode());
        if (stnEntity == null) {
            return;
        }

        //agv主动取放货至货架，更新对应库存信息
        if (RcsConstants.HK_METHOD_PUT.equals(dto.getMethod())) {
            //记录日志
            this.save(dto);
            if (stnEntity.getStationType().equals("ST")) {
                return;
            }
            //收到从室外到货架上的搬运结束通知时，需要将货架状态设置为有货,并生成库存信息
            StockEntity stock = new StockEntity();
            stock.setContNo(dto.getPodCode());
            stock.setPositionType(stnEntity.getStationType());
            stock.setCurPosition(dto.getCurrentPositionCode());
            stock.setStockQty(BigDecimal.valueOf(1));
            stock.setCreator(WcsConstants.WCS_USER_ID);
            stock.setUpdater(WcsConstants.WCS_USER_ID);
            stock.setCreateDate(new Date());
            stockService.insert(stock);

            StnMappingEntity stnMappingEntity = stnMappingService.getStnByNo(dto.getCurrentPositionCode());
            stnMappingEntity.setStatus(2);
            stnMappingEntity.setContNo(dto.getPodCode());
            stnEntity.setUpdater(WcsConstants.WCS_USER_ID);
            stnEntity.setUpdateDate(new Date());
            stnMappingService.updateById(stnMappingEntity);

        } else if (RcsConstants.HK_METHOD_GET.equals(dto.getMethod())) {
            //记录日志
            this.save(dto);

            //收到货架框搬运到室外的搬运开始通知时，需要将货架状态和库存清空
//            StockEntity stockEntity = stockService.findByCurPosition(dto.getCurrentPositionCode());
            List<StockEntity> stockEntities = stockDao.selectList(new QueryWrapper<StockEntity>().lambda().eq(StockEntity::getCurPosition, dto.getCurrentPositionCode()));
            if (ObjectUtils.isNotEmpty(stockEntities)) {
                for (StockEntity stockEntity : stockEntities) {
                    stockService.deleteById(stockEntity.getId());
                }
            }
            StnMappingEntity stnMappingEntity = stnMappingService.getStnByNo(dto.getCurrentPositionCode());
            stnMappingEntity.setStatus(0);
            stnMappingEntity.setContNo("");
            stnEntity.setUpdater(WcsConstants.WCS_USER_ID);
            stnEntity.setUpdateDate(new Date());
            stnMappingService.updateById(stnMappingEntity);

        }
        //记录日志
        logWorkService.workLogging(workName, dto.getReqCode(), pCode,
                pMsg, null, workProc, WcsConstants.WCS_USER_NAME, 10L);
    }
}
